package tx.os3.clientserver.client.connection;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;

final class ServerConnection {

    private static ServerConnection instance;
    private static final String HOST = "localhost";
    private static final int PORT = 3000;

    private Socket socket;
    private BufferedReader input;
    private PrintWriter output;

    private ServerConnection() throws UnknownHostException, IOException {

        this.socket = new Socket(HOST, PORT);
        this.input = new BufferedReader(new InputStreamReader(
                this.socket.getInputStream()));
        this.output = new PrintWriter(this.socket.getOutputStream(), false);
    }

    public static ServerConnection getInstance() throws UnknownHostException,
    IOException {
        if(instance == null) {
            instance = new ServerConnection();
        }
        return instance;
    }

    /**
     * Closes the server connection. After closing the connection instance
     * cannot be used anymore.
     */
    public void close() {
        if(this.socket != null) {
            try {
                this.socket.close();
                this.socket = null;
                instance = null;
            }
            catch(IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public byte[] writeBinaryResult(String data) {
        this.writeData(data, null);
        int fileSize = 0;
        try {
            fileSize = Integer.parseInt(this.input.readLine());
        }
        catch(NumberFormatException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        catch(IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        // Read file content
        byte[] fileContent = new byte[fileSize];
        try {
            int read = 0;

            do {
                read += this.socket.getInputStream().read(fileContent, read,
                        fileSize - read);
            } while(read < fileSize);
            
            // Read closing new line
            this.input.readLine();
        }
        catch(IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return fileContent;
    }

    public String write(String data) {
        return this.write(data, null);
    }

    /**
     * Writes the given data to the socket.
     * 
     * @param data
     *            The data to write.
     * @throws IOException
     */
    public String write(String data, byte[] binaryData) {
        this.writeData(data, binaryData);
        String returnString = "";
        try {
            String currentLine;
            while((currentLine = this.input.readLine()) != null
                    && !currentLine.isEmpty()) {
                System.out.println(currentLine);
                returnString += currentLine + "\n";
            }
        }
        catch(IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return returnString;
    }

    private void writeData(String data, byte[] binaryData) {
        if(!this.socket.isConnected()) {
            throw new IllegalStateException(
                    "Socket is not connected to server.");
        }

        this.output.write(data + "\n");
        this.output.flush();
        if(binaryData != null) {
            try {
                this.socket.getOutputStream().write(binaryData, 0,
                        binaryData.length);
            }
            catch(IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
